package conMgr.ui.util;

import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;

import conMgr.model.User;
import conMgr.model.UserType;
import conMgr.ui.bases.JDialogEx;

/**
 * Provides a dialog that lets the user select from the list of all users based
 * on type. 
 * @author is4@uw.edu
 */
public class SelectUserView extends JDialogEx
{
	/**
	 * The serialization ID for this class.
	 */
	private static final long serialVersionUID = -2214412840263723978L;
	
	/**
	 * The button bar for this dialog.
	 */
	private final ButtonBar buttonBar;
	
	/**
	 * The selected users. This list starts empty but will be filled with one
	 * or more users when the active user presses the OK button.
	 */
	private final List<User> selectedUsers;
	
	/**
	 * The list of users of the specified type.
	 */
	private final List<User> users;
	
	/**
	 * The table of available users.
	 */
	private final JTable userTable;
	
	/**
	 * Initializes a new Select User View.
	 * @param type The type of users to display.
	 * @param multiSelect True if multiple users are selectable; otherwise,
	 * false.
	 */
	private SelectUserView(final UserType type, final boolean multiSelect)
	{
		selectedUsers = new LinkedList<User>();
		
		setTitle("Select a " + type.toString());
		
		users = getAvailableUsers(type);
		Collections.sort(users);
		userTable = addTable(multiSelect);
		
		final GridBagConstraints constraints = new GridBagConstraints();
		constraints.insets = Ui.DEFAULT_INSETS;
		constraints.gridx = 0;
		constraints.gridy = 1;
		constraints.anchor = GridBagConstraints.NORTHEAST;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		buttonBar = new ButtonBar();
		buttonBar.addButton("Select", new OkAction());
		buttonBar.addButton("Cancel", new CancelAction());
		add(buttonBar, constraints);
		
		pack();
		setLocationRelativeTo(null);
	}
	
	/**
	 * Adds the user table to the dialog.
	 * @param multiSelect True if multiple users are selectable; otherwise,
	 * false.
	 * @return The table.
	 */
	private JTable addTable(final boolean multiSelect)
	{
		final GridBagConstraints constraints = new GridBagConstraints();
		constraints.insets = Ui.DEFAULT_INSETS;
		constraints.gridx = 0;
		constraints.gridy = 0;
		constraints.anchor = GridBagConstraints.CENTER;
		
		final JTable table = new JTable(new UserTableModel(users));
		Ui.packTable(table);
		
		if (multiSelect)
			table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		else
			table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		
		final JScrollPane pane = new JScrollPane(table);
		add(pane, constraints);
		
		return table;
	}
	
	/**
	 * Gets a list of users matching the given type. 
	 * @param type The type of users to display.
	 * @return A list of users matching the given type.
	 */
	private List<User> getAvailableUsers(final UserType type)
	{
		final List<User> users = new ArrayList<User>();
		
		for (User user : User.getAllUsers())
			if (user.getType().equals(type) && !user.equals(User.getCurrentUser()))
				users.add(user);
		
		return users;
	}
	
	/**
	 * Gets a user by displaying this dialog.
	 * @param type The type of users to display.
	 * @return The selected user or null if none was selected.
	 */
	public static User getUser(final UserType type)
	{
		final SelectUserView view = new SelectUserView(type, false);
		
		view.setVisible(true);
	
		if (!view.selectedUsers.isEmpty())
			return view.selectedUsers.get(0);
		return null;
	}
	
	/**
	 * Gets a list of users by displaying this dialog.
	 * @param type The type of users to display.
	 * @return The list of selected users or null if none were selected.
	 */
	public static List<User> getUsers(final UserType type)
	{
		final SelectUserView view = new SelectUserView(type, true);
		
		view.setVisible(true);
		
		return view.selectedUsers;
	}
	
	/**
	 * Provides an action for the OK button. 
	 */
	class OkAction extends AbstractAction
	{
		/**
		 * The serialization ID of this class.
		 */
		private static final long serialVersionUID = 6148820423621061547L;

		/**
		 * Handles the action. Creates or updates the given paper and closes the
		 * window.
		 */
		@Override
		public void actionPerformed(final ActionEvent arg0)
		{
			if (userTable.getSelectedRows().length == 0)
			{
				JOptionPane.showMessageDialog
				(
					null,
					"Please select a user from the list.",
					"No User Selected",
					JOptionPane.ERROR_MESSAGE
				);
				return;
			}
			
			for (int i : userTable.getSelectedRows())
				selectedUsers.add(users.get(i));

			SelectUserView.this.close();
		}
	}
	
	/**
	 * Provides an action for the Cancel button.
	 */
	class CancelAction extends AbstractAction
	{
		/**
		 * The serialization ID of this class.
		 */
		private static final long serialVersionUID = -3826281226019327775L;

		/**
		 * Handles the action. Closes the window.
		 */
		@Override
		public void actionPerformed(final ActionEvent arg0)
		{
			SelectUserView.this.close();
		}
	}
	
	/**
	 * Provides a table model for user classes.
	 * @author is4@uw.edu
	 */
	class UserTableModel extends AbstractTableModel
	{
		/**
		 * The serialization ID of this class.
		 */
		private static final long serialVersionUID = 4419841090731448484L;

		/**
		 * The list of users to display.
		 */
		private final List<User> users;
		
		/**
		 * Initializes a new user table model.
		 * @param users The list of users to display.
		 */
		private UserTableModel(final List<User> users)
		{
			this.users = users;
		}
		
		/**
		 * Gets the number of columns to display.
		 */
		@Override
		public int getColumnCount()
		{
			return 3;
		}

		/**
		 * Gets the name of the column at the specified index.
		 * @param column The column to get the name of.
		 * @return The name of the column at the specified index. 
		 */
		@Override
		public String getColumnName(int column)
		{
			switch (column)
			{
				case 0: return "Name";
				case 1: return "Email";
				case 2: return "Type";
				default: return "";
			}
		};
		
		/**
		 * Gets the number of rows to display.
		 */
		@Override
		public int getRowCount()
		{
			return users.size();
		}

		/**
		 * Gets the value at the given row and column.
		 * @param row The row to get the value for.
		 * @param column The column to get the value for.
		 */
		@Override
		public Object getValueAt(final int row, final int column)
		{
			final User user = users.get(row);
			
			switch (column)
			{
				case 0: return user.getName();
				case 1: return user.getEmail();
				case 2: return user.getType().getFriendlyName();
				default: return "";
			}
		}
	}
}
